package com.pinfly.common.crypto;

import java.io.File;
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyStore;
import java.util.Properties;

import org.apache.log4j.Logger;

import com.pinfly.common.config.BaseConfigConstants;
import com.pinfly.common.config.PfyProperties;
import com.pinfly.common.config.PfyPropertiesFactory;
import com.pinfly.common.util.StringUtil;

/**
 * Provides an implementation of the ICryptoKey interface. This will read the
 * key from the keystore file in the common directory. The details to read the
 * key store are in the cryptokeys configuration file.
 */
public class CryptoKeyFromKeyStore implements ICryptoKey
{
    private static final Logger logger = Logger.getLogger (CryptoKeyFromKeyStore.class);
    private static final String PROP_GROUP = "cryptokeys";
    private static final String PROP_PREFIX = "keystore.";
    private static final String PROP_FILE = "file";
    private static final String PROP_ALIAS = "alias";
    private static final String PROP_STORE_PASS = "storePass";
    private static final String PROP_KEY_PASS = "keyPass";

    private Key m_key;
    private boolean m_init = false;

    private void init () throws CryptoException
    {
        try
        {
            PfyProperties cfgProp = PfyPropertiesFactory.getInstance ().getProperties (PROP_GROUP);
            if (cfgProp != null)
            {
                Properties prop = cfgProp.getSubProperties (PROP_PREFIX);
                if (prop != null)
                {
                    String fileName = prop.getProperty (PROP_FILE);
                    boolean badCfg = false;
                    if (StringUtil.isNullOrBlank (fileName))
                    {
                        logger.warn (PROP_PREFIX + PROP_FILE + " is not found in " + PROP_GROUP + " properties");
                        badCfg = true;
                    }

                    String alias = prop.getProperty (PROP_ALIAS);
                    if (StringUtil.isNullOrBlank (alias))
                    {
                        logger.warn (PROP_PREFIX + PROP_ALIAS + " is not found in " + PROP_GROUP + " properties");
                        badCfg = true;
                    }

                    String storePass = prop.getProperty (PROP_STORE_PASS);
                    if (StringUtil.isNullOrBlank (storePass))
                    {
                        logger.warn (PROP_PREFIX + PROP_STORE_PASS + " is not found in " + PROP_GROUP + " properties");
                        badCfg = true;
                    }

                    String keyPass = prop.getProperty (PROP_KEY_PASS);
                    if (StringUtil.isNullOrBlank (keyPass))
                    {
                        logger.warn (PROP_PREFIX + PROP_KEY_PASS + " is not found in " + PROP_GROUP + " properties");
                        badCfg = true;
                    }

                    if (!badCfg)
                    {
                        String commonConfigDir = System.getProperty (BaseConfigConstants.COMMON_PROPERTY_DIR);
                        File keystoreFile = new File (commonConfigDir + File.separator + "keystore" + File.separator
                                                      + fileName);

                        if (keystoreFile.exists ())
                        {

                            final KeyStore keyStore = KeyStore.getInstance ("JCEKS");

                            final FileInputStream input = new FileInputStream (keystoreFile);
                            keyStore.load (input, storePass.toCharArray ());
                            input.close ();

                            if (keyStore.containsAlias (alias))
                            {
                                m_key = keyStore.getKey (alias, keyPass.toCharArray ());
                                m_init = true;
                            }
                            else
                            {
                                logger.warn ("Alias is not found: " + alias);
                            }

                        }
                        else
                        {
                            logger.warn ("Unable to find file: " + keystoreFile.toString ());
                        }
                    }
                    else
                    {
                        logger.warn ("Unable to retrieve crypto keys from keystore");
                    }
                }
                else
                {
                    logger.warn ("Unable to find prefix (" + PROP_PREFIX + ") in config file: " + PROP_GROUP);
                    throw new CryptoException ("Unable to find prefix (" + PROP_PREFIX + ") in config file: "
                                               + PROP_GROUP);
                }
            }
            else
            {
                logger.warn ("Unable to find config file: " + PROP_GROUP);
                throw new CryptoException ("Unable to find config file: " + PROP_GROUP);
            }
        }
        catch (Exception e)
        {
            logger.warn ("Unable to retrieve keys from keystore: " + PROP_GROUP, e);
            throw new CryptoException (e);
        }
    }

    @Override
    public Key getKey ()
    {
        if (!m_init)
        {
            try
            {
                init ();
            }
            catch (CryptoException e)
            {
                logger.warn ("Unable to create key", e);
            }
        }

        return m_key;
    }

}
